﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace Digitalmes.ControlEx;

/// <summary>
/// LED 画布
/// </summary>
public partial class LedCanvas : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    /// <summary>
    /// 配置名称
    /// </summary>
    public string? ProfileName { get; private set; }

    /// <summary>
    /// 是否允许用鼠标拖拽 Led 控件
    /// </summary>
    public bool AllowMouseDrop { get; set; }

    /// <summary>
    /// 获取或设置图片目录，默认为 ./Assets/Images/ 目录。
    /// </summary>
    public string ImageBaseDirectory { get; set; } = Path.Combine(AppContext.BaseDirectory, "Assets", "Images");

    public LedCanvas()
    {
        InitializeComponent();
        DataContext = this;
    }

    private double _canvasWidth;
    public double CanvasWidth
    {
        get { return _canvasWidth; }
        set { _canvasWidth = value; OnPropertyChanged(nameof(CanvasWidth)); }
    }

    private double _canvasHeight;
    public double CanvasHeight
    {
        get { return _canvasHeight; }
        set { _canvasHeight = value; OnPropertyChanged(nameof(CanvasHeight)); }
    }

    /// <summary>
    /// 更改配置。配置更改后会重新加载所有的点位。
    /// </summary>
    /// <param name="profile">配置项</param>
    public void ChangeProfile(LedProfile profile)
    {
        ProfileName = profile.Name;
        CanvasWidth = profile.CanvasWidth;
        CanvasHeight = profile.CanvasHeight;

        var imagePath = Path.Combine(ImageBaseDirectory, profile.ImageName);
        if (Path.Exists(imagePath))
        {
            CanvasImage.Source = new BitmapImage(new Uri(imagePath));
        }

        PointCanvas.Children.Clear(); // 情况点位
        foreach (var point in profile.Points)
        {
            AddLed(point);
        }
    }

    /// <summary>
    /// 常规索引状态。
    /// </summary>
    /// <remarks>
    /// index 为当前处理完的索引，处理完后下一个（若有）会变为 Todo 状态；在 index 为 0 时，所有状态都更改为 None 。
    /// </remarks>
    /// <param name="group">索引分组，没有分组设置为空</param>
    /// <param name="index">索引。</param>
    /// <param name="isOk">处理结果，true 状态为 OK，false 状态为 NG。</param>
    /// <param name="delay">延迟切换时长（毫秒）</param>
    public async Task ChangeStateAsync(string group, int index, bool isOk = true, int delay = 500)
    {
        var children = PointCanvas.Children
            .OfType<Led>()
            .Where(s => s.Group == group)
            .OrderBy(s => s.Index)
            .ToList();
        if (children.Count == 0)
        {
            return;
        }

        // 索引为 0，表示将要重新开始
        if (index == 0)
        {
            // 将第一个设为 Todo，其他设为 None
            var first = children.First();
            children.ForEach(s =>
            {
                s.State = LedState.None;
            });

            if (delay > 0)
            {
                await Task.Delay(delay).ConfigureAwait(false);
            }
            first.State = LedState.Todo;

            return;
        }

        // 将当前更改为 OK/NG 状态
        var led = children.FirstOrDefault(s => s.Index == index);
        if (led != null)
        {
            led.State = isOk ? LedState.OK : LedState.NG;
        }

        // 不是最后一个，将下一个设为 Todo 状态
        if (index < children.Count)
        {
            var led2 = children.FirstOrDefault(s => s.Index > index);
            if (led2 != null)
            {
                if (delay > 0)
                {
                    await Task.Delay(delay).ConfigureAwait(false);
                }

                led2.State = LedState.Todo;
            }
        }
    }

    /// <summary>
    /// 重置所有 LED 状态。将第一个重置为 Todo 状态，其他 LED 重置为 None 状态，。
    /// </summary>
    public void ResetState()
    {
        var children = PointCanvas.Children
            .OfType<Led>()
            .OrderBy(s => s.Index)
            .ToArray();
        if (children.Length == 0)
        {
            return;
        }

        // 将第一个设为 Todo，其他设为 None
        for (var i = 0; i < children.Length; i++)
        {
            var led = children[i];
            led.State = i == 0 ? LedState.Todo : LedState.None;
        }
    }

    /// <summary>
    /// 添加 LED
    /// </summary>
    /// <param name="point"></param>
    public void AddLed(LedPoint point)
    {
        Led led = new()
        {
            Diameter = point.Diameter,
            Text = point.Text,
            Index = point.Index,
            Group = point.Group,
            State = point.State,
        };
        if (!string.IsNullOrEmpty(point.TextColor))
        {
            led.TextColor = point.TextColor;
        }
        if (point.TextFontSize.HasValue)
        {
            led.TextFontSize = point.TextFontSize.Value;
        }
        if (!string.IsNullOrEmpty(point.NoneStateColor))
        {
            led.LedStateNoneColor = point.NoneStateColor;
        }
        if (!string.IsNullOrEmpty(point.OkStateColor))
        {
            led.LedStateOkColor = point.OkStateColor;
        }
        if (!string.IsNullOrEmpty(point.NgStateColor))
        {
            led.LedStateNgColor = point.NgStateColor;
        }

        led.PreviewMouseDown += (sender, e) =>
        {
            var control = (Led)sender;
            if (AllowMouseDrop && !control.IsPreviewMouseDown)
            {
                control.IsPreviewMouseDown = true;
                control.MouseDownPosition = e.GetPosition(this); // 获取鼠标位置
                control.CaptureMouse();
            }
        };
        led.PreviewMouseMove += (sender, e) =>
        {
            var control = (Led)sender;
            if (AllowMouseDrop && control.IsPreviewMouseDown)
            {
                var pos = e.GetPosition(this);
                var dp = pos - control.MouseDownPosition;
                var x = control.CanvasPosition.X + dp.X;
                var y = control.CanvasPosition.Y + dp.Y;

                // 不允许移动超出边界
                if (x < 0 || x > PointCanvas.Width
                    || y < 0 || y > PointCanvas.Height)
                {
                    return;
                }

                Canvas.SetLeft(control, x);
                Canvas.SetTop(control, y);
            }
        };
        led.PreviewMouseUp += (sender, e) =>
        {
            var control = (Led)sender;
            if (AllowMouseDrop && control.IsPreviewMouseDown)
            {
                control.IsPreviewMouseDown = false;
                control.ReleaseMouseCapture();

                // 鼠标松开时更新Led当前位置
                control.CanvasPosition = new Point(Canvas.GetLeft(control), Canvas.GetTop(control)); 
            }
        };

        PointCanvas.Children.Add(led);
        Canvas.SetLeft(led, point.X);
        Canvas.SetTop(led, point.Y);

        // 计算Led当前位置
        led.CanvasPosition = new Point(Canvas.GetLeft(led), Canvas.GetTop(led)); 
    }

    /// <summary>
    /// 获取 Led 集合
    /// </summary>
    /// <returns></returns>
    public IReadOnlyList<Led> GetCollection()
    {
        return PointCanvas.Children
            .OfType<Led>()
            .ToList();
    }

    protected internal virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
